import sys, os, time, string, glob
from subprocess import *

def system(cmd):
    return Popen(cmd, shell=True, stdout=PIPE).stdout.read()

# any reboot-safe machine id
MACHINE_ID = system('ssh-keygen  -l -f /etc/ssh/ssh_host_rsa_key 2>/dev/null').split()[1].replace(':','')
assert 32==len(MACHINE_ID)


def collect_sysinfo():
    SYSINFO = {}

    SYSINFO['machine_id'] = MACHINE_ID

    #SYSINFO['time'] = int(system('date +%s').strip())
    SYSINFO['time'] = time.time()

    SYSINFO['hostname'] = system('hostname -f').strip()

    uptime, idletime = file('/proc/uptime').read().split()
    SYSINFO['uptime'] = float(uptime)
    SYSINFO['idletime'] = float(idletime)

    SYSINFO['df'] = []
    for line in system('df -l --block-size=1').strip().split('\n')[1:]:
        device, total, used, avail, use, mount = line.split()
        SYSINFO['df'].append ({
            'mount' : mount,
            'device': device,
            'total' : int(total),
            'used'  : int(used),
            'avail' : int(avail)
        })

    la1, la5, la10, proccount, lastpid = file('/proc/loadavg').read().split()
    SYSINFO['la1'] = float(la1)
    SYSINFO['la5'] = float(la5)
    SYSINFO['la10'] = float(la10)
    SYSINFO['rproc'], SYSINFO['nproc'] = map(int, proccount.split('/'))

    H = {}
    for procname in system("cat /proc/*/status | grep ^Name | awk '{print $2}' | sort").split():
        procname = procname.split('/')[0]
        H[procname] = H.get(procname, 0) + 1
    SYSINFO['proccount'] = []
    for procname, count in H.iteritems():
        SYSINFO['proccount'].append ({
            'name'  : procname,
            'count' : count,
        })

    SYSINFO['memory'] = {}
    for line in file('/proc/meminfo').readlines():
        name, value = map(string.strip, line.split(':'))
        if value.endswith(' kB'):
            value = int(value[:-3]) * 1024
        else:
            value = int(value)
        if name in ('MemTotal', 'MemFree', 'Active'):
            SYSINFO['memory'][name] = value

    SYSINFO['version'] = {
        'kernel'  : system("uname --release").strip(),
        'sshd'    : system("/usr/sbin/sshd -f 2>&1 | perl -ne 'print $1 if /OpenSSH_([0-9a-z.]+)/im'").strip(),
        'named'   : system("/usr/sbin/named -v | perl -ne 'print $1 if /BIND\s+([0-9.]+)/im'").strip(),
        'bash'    : system("bash --version | perl -ne 'print $1 if /version\s+(\S+)\s/i'").strip(),
        'ld'      : system("ld --version   | perl -ne 'if (/(\d[\d\.]+)/) {print $1;exit}'").strip(),
        'gcc'     : system("gcc --version  | perl -ne 'if (/(\d[\d\.]+)/) {print $1;exit}'").strip(),
        'perl'    : system("perl -v        | perl -ne 'if (/(\d[\d\.]+)/) {print $1;exit}'").strip(),
        'erlang'  : system("erl +V 2>&1").strip(),
        'python'  : system("python -V 2>&1 | perl -ne 'if (/(\d[\d\.]+)/) {print $1;exit}'").strip(),
        'geoip'   : system("grep -a -z \"^GEO-106\" /usr/share/GeoIP/GeoIP.dat | perl -ne 'print $1 if /^GEO-106\s*(.*?)\s+Copyright/i'").strip(),
    }

    SYSINFO['net'] = {}
    for line in file('/proc/net/dev').readlines()[2:]:
        iface, numbers = line.split(':')
        iface = iface.strip()
        numbers = map(int, numbers.split())
        SYSINFO['net'][iface] = {
            'rxbytes'       : numbers[0],
            'rxpackets'     : numbers[1],
            'rxerrs'        : numbers[2],
            'rxdrop'        : numbers[3],
            'rxfifo'        : numbers[4],
            'rxframe'       : numbers[5],
            'rxcompressed'  : numbers[6],
            'rxmulticast'   : numbers[7],
            'txbytes'       : numbers[8],
            'txpackets'     : numbers[9],
            'txerrs'        : numbers[10],
            'txdrop'        : numbers[11],
            'txfifo'        : numbers[12],
            'txcolls'       : numbers[13],
            'txcarrier'     : numbers[14],
            'txcompressed'  : numbers[15],
        }

    for iface in SYSINFO['net'].keys():
        SYSINFO['net'][iface]['ip'] = system("ifconfig %s | perl -ne 'print $1 if s/inet addr:(.+?) //;'" % iface)

    # sysinfo.d/ will be executed during sysinfo collection
    for filename in glob.glob(os.path.join(os.path.dirname(sys.argv[0]), 'sysinfo.d', '*')):
        filename = os.path.join('sysinfo.d', filename)
        if os.access(filename, os.X_OK):
            pass

    return SYSINFO

if __name__=='__main__':
    print collect_sysinfo()